<template>
    <div class="container" ref="container">
        <audio src="/井内啓二 - 急駛の冒険者.mp3" loop ref="audio"></audio>
        <div class="hp">当前血量为:{{ hp }}</div>
        <div class="info">
            <span v-if="guanqia < 4">当前为第{{ guanqia }}关, 共杀死怪物 {{ killNum }}只 </span>
            <span v-else>当前为第{{ guanqia }}关, 请击杀最终BOSS,BOSS血量为{{ bossHp }} </span>
        </div>
        <div class="setting-btn" @click="() => {
            if (!isDead) showSetting = true;
        }
            ">
            设置
        </div>
        <div class="setting" v-show="showSetting">
            <div class="close" @click="showSetting = false">X</div>
            <div class="title">设置</div>
            <div class="content">
                <div class="btn" @click="closeAudio">
                    音乐{{ audioNo ? "关闭" : "打开" }}
                </div>
                <div class="btn" @click="openFullscreen" v-if="!isfullscreen">全屏</div>
                <div class="btn" @click="closeFullscreen" v-else>退出全屏</div>
                <div class="btn" @click="emit('end')">主界面</div>
            </div>
        </div>
        <div class="dead-tip" v-show="isDead">
            <div class="title">提示</div>
            <p>你已死亡,游戏失败了!</p>
            <div class="btn" @click="emit('end')">主界面</div>
        </div>
        <div class="success-tip" v-show="isSuccess">
            <div class="title">提示</div>
            <p v-if="guanqia < 4">恭喜你!通关了</p>
            <p v-else>恭喜你,通关了游戏所有关卡!</p>
            <div class="btn" @click="next" v-if="guanqia < 4">下一关卡</div>
            <div class="btn" @click="emit('end')" v-else>主界面</div>
        </div>
    </div>
</template>

<script setup>
import * as PIXI from "pixi.js";
import PersonSprite from "@/js/PersonSprite.js";
import GroundSprite from "@/js/GroundSprite.js";
import EnemySprite from "@/js/EnemySprite.js";
import BossSprite from "@/js/BossSprite.js";
import { onMounted, ref, watch } from "vue";

const emit = defineEmits(["end"]);

const showSetting = ref(false);
const isDead = ref(false);

const killNum = ref(0);
const isSuccess = ref(false);
const guanqia = ref(1);

const audio = ref();
const audioNo = ref(true);

function closeAudio() {
    audioNo.value = !audioNo.value;
    if (audioNo.value) {
        audio.value.play();
    } else {
        audio.value.pause();
    }
}

let next = () => { };

const container = ref();
const isfullscreen = ref(false);

function openFullscreen() {
    if (document.documentElement.requestFullscreen) {
        document.documentElement.requestFullscreen();
    } else if (document.documentElement.mozRequestFullScreen) {
        // Firefox
        document.documentElement.mozRequestFullScreen();
    } else if (document.documentElement.webkitRequestFullscreen) {
        // Chrome and Safari
        document.documentElement.webkitRequestFullscreen();
    } else if (document.documentElement.msRequestFullscreen) {
        // IE/Edge
        document.documentElement.msRequestFullscreen();
    }
    isfullscreen.value = true;
}
function closeFullscreen() {
    if (document.exitFullscreen) {
        document.exitFullscreen();
    } else if (document.mozCancelFullScreen) {
        // Firefox
        document.mozCancelFullScreen();
    } else if (document.webkitExitFullscreen) {
        // Chrome and Safari
        document.webkitExitFullscreen();
    } else if (document.msExitFullscreen) {
        // IE/Edge
        document.msExitFullscreen();
    }
    isfullscreen.value = false;
}

const hp = ref();
const bossHp = ref();
const isBossAttack = ref(false)
let enemySpriteList = [];
const isForEndList = ref([]);
let oldIsForEndList = [];

onMounted(() => {
    audio.value.volume = 0.5;
    alert("开始游戏");
    audio.value.play();

    const app = new PIXI.Application({
        width: window.innerWidth,
        height: window.innerHeight,
        background: "white",
    });
    container.value.appendChild(app.view);

    let groundSprite = new GroundSprite(app);
    app.stage.addChild(groundSprite.container);

    let personSprite = new PersonSprite();
    app.stage.addChild(personSprite.container);
    hp.value = personSprite.hp;

    let bossSprite = null

    let timer = setInterval(() => {
        if (isDead.value || isSuccess.value) return;
        let sum = 0;
        enemySpriteList.forEach((item) => {
            if (item.hp > 0) {
                sum += 1;
            }
        });
        if (sum < 5) {
            let enemySprite = new EnemySprite();
            app.stage.addChild(enemySprite.container);
            enemySpriteList.push(enemySprite);
            isForEndList.value.push(false);
        }
    }, 5000);

    let keySet = new Set();

    next = () => {
        groundSprite.switchMap();
        guanqia.value = groundSprite.index;
        isSuccess.value = false;
        keySet = new Set();
        personSprite.container.position.set(50, 415);
        personSprite.hp = 10;
        hp.value = 10;
        killNum.value = 0;
        let children = app.stage.children;
        while (children.length > 2) {
            app.stage.removeChild(children[children.length - 1]);
        }
        enemySpriteList = [];
        isForEndList.value = [];
        if (guanqia.value == 4) {
            clearInterval(timer)
            bossSprite = new BossSprite();
            bossSprite.container.position.set(app.screen.width / 2, app.screen.height / 2)
            app.stage.addChild(bossSprite.container);
            bossHp.value = bossSprite.hp
        }
    };

    let b = new Bump(PIXI);

    watch(
        () => isForEndList,
        (newVal) => {
            newVal.value.forEach((item, index) => {
                if (item != oldIsForEndList[index]) {
                    if (item) {
                        personSprite.hurt();
                        hp.value = personSprite.hp;
                        if (personSprite.hp <= 0) {
                            isDead.value = true;
                            keySet = new Set();
                            personSprite.dead();
                        }
                    }
                }
            });
        },
        { deep: true }
    );

    watch(isBossAttack, newVal => {
        if (newVal) {
            personSprite.hurt()
            hp.value = personSprite.hp;
            if (personSprite.hp <= 0) {
                isDead.value = true;
                keySet = new Set();
                personSprite.dead();
            }
        }
    })
    app.ticker.add((detal) => {
        if (isDead.value || isSuccess.value) return;
        if (guanqia.value == 4) {
            // 计算从敌人到玩家的方向向量
            const directionX = personSprite.container.x - bossSprite.container.x;
            const directionY = personSprite.container.y - bossSprite.container.y;
            // 计算距离
            const distance = Math.sqrt(
                directionX * directionX + directionY * directionY
            );
            // 避免除以零的错误，当距离为零时（即敌人和玩家在同一位置）不移动
            if (distance > 50) {
                const normalizedDirectionX = directionX / distance;
                const normalizedDirectionY = directionY / distance;

                // 根据速度更新敌人的位置
                bossSprite.container.x += normalizedDirectionX * 2;
                bossSprite.container.y += normalizedDirectionY * 2;
            } else {
                let isBump = b.hit(personSprite.container, bossSprite.container)
                if (isBump) {
                    if (
                        bossSprite.container.currentFrame ==
                        bossSprite.bossTexture.length - 1
                    ) {
                        isBossAttack.value = true
                    } else {
                        isBossAttack.value = false
                    }
                }
            }
        }
        enemySpriteList.forEach((enemySprite, index) => {
            if (enemySprite.hp < 0) return;
            // 计算从敌人到玩家的方向向量
            const directionX = personSprite.container.x - enemySprite.container.x;
            const directionY = personSprite.container.y - enemySprite.container.y;
            // 计算距离
            const distance = Math.sqrt(
                directionX * directionX + directionY * directionY
            );
            let num
            if (directionX > 0) {
                num = 55
            } else {
                num = 90
            }
            // 避免除以零的错误，当距离为零时（即敌人和玩家在同一位置）不移动
            if (distance > num) {
                const normalizedDirectionX = directionX / distance;
                const normalizedDirectionY = directionY / distance;
                // 归一化方向向量
                if (normalizedDirectionX < 0) {
                    enemySprite.container.scale.x = -1;
                } else {
                    enemySprite.container.scale.x = 1;
                }
                enemySprite.attackNum = 0;
                enemySprite.runNum += 1;
                if (enemySprite.runNum == 1) {
                    enemySprite.run();
                }
                // 根据速度更新敌人的位置
                enemySprite.container.x += normalizedDirectionX * 2;
                enemySprite.container.y += normalizedDirectionY * 2;
            } else {
                enemySprite.runNum = 0;
                enemySprite.attackNum += 1;
                if (enemySprite.attackNum == 1) {
                    enemySprite.attack();
                }
                oldIsForEndList = [...isForEndList.value];
                if (
                    enemySprite.container.currentFrame ==
                    enemySprite.attackTexture.length - 1
                ) {
                    isForEndList.value[index] = true;
                } else {
                    isForEndList.value[index] = false;
                }
            }
        });
    });

    let num = 0;
    let speed = 10;

    window.addEventListener("keydown", (e) => {
        if (isDead.value || isSuccess.value) return;
        keySet.add(e.key);
        let arr = Array.from(keySet);
        if (
            arr.includes("w") ||
            arr.includes("s") ||
            arr.includes("a") ||
            arr.includes("d")
        ) {
            e.preventDefault();
            num += 1;
            if (num == 1) {
                personSprite.container.textures = personSprite.runTexture;
                personSprite.container.play();
            }
        }
        if (arr.includes("a")) {
            personSprite.container.anchor.set(1, 0);
            personSprite.container.scale.x = -1;
            if (groundSprite.container.tilePosition.x < 0) {
                groundSprite.container.tilePosition.x += 10;
                enemySpriteList.forEach((enemySprite) => {
                    enemySprite.container.x += speed;
                });
                if (bossSprite) {
                    bossSprite.container.x += speed;
                }
            }
        }
        if (arr.includes("w")) {
            if (groundSprite.container.tilePosition.y < 0) {
                groundSprite.container.tilePosition.y += 10;
                enemySpriteList.forEach((enemySprite) => {
                    enemySprite.container.y += speed;
                });
                if (bossSprite) {
                    bossSprite.container.y += speed;
                }
            }
        }
        if (arr.includes("s")) {
            let bottom =
                groundSprite.container.height -
                groundSprite.container.texture.height / 2;
            if (groundSprite.container.tilePosition.y > bottom) {
                groundSprite.container.tilePosition.y -= 10;
                enemySpriteList.forEach((enemySprite) => {
                    enemySprite.container.y -= speed;
                });
                if (bossSprite) {
                    bossSprite.container.y -= speed;
                }
            }
        }
        if (arr.includes("d")) {
            let right =
                groundSprite.container.width - groundSprite.container.texture.width / 2;
            if (groundSprite.container.tilePosition.x > right) {
                groundSprite.container.tilePosition.x -= 10;
                enemySpriteList.forEach((enemySprite) => {
                    enemySprite.container.x -= speed;
                });
                if (bossSprite) {
                    bossSprite.container.x -= speed;
                }
            }
        }
        if (arr.includes("w") && arr.includes("d")) {
            personSprite.container.x += speed;
            personSprite.container.y -= speed;
        } else if (arr.includes("w") && arr.includes("a")) {
            personSprite.container.x -= speed;
            personSprite.container.y -= speed;
        } else if (arr.includes("s") && arr.includes("d")) {
            personSprite.container.x += speed;
            personSprite.container.y += speed;
        } else if (arr.includes("s") && arr.includes("a")) {
            personSprite.container.x -= speed;
            personSprite.container.y += speed;
        } else if (arr.includes("w") && !arr.includes("s")) {
            personSprite.container.y -= speed;
        } else if (arr.includes("a") && !arr.includes("d")) {
            personSprite.container.x -= speed;
        } else if (arr.includes("s") && !arr.includes("w")) {
            personSprite.container.y += speed;
        } else if (arr.includes("d") && !arr.includes("a")) {
            personSprite.container.x += speed;
        }
        if (personSprite.container.y < 350) {
            personSprite.container.y = 350;
        }
        if (personSprite.container.y > groundSprite.container.height - 230) {
            personSprite.container.y = groundSprite.container.height - 230;
        }
        if (personSprite.container.x < 50) {
            personSprite.container.x = 50;
        }
        if (personSprite.container.x > groundSprite.container.width - 100) {
            personSprite.container.x = groundSprite.container.width - 100;
        }
    });

    window.addEventListener("keyup", (e) => {
        if (isDead.value || isSuccess.value) return;
        keySet.delete(e.key);
        num = 0;
        if (e.key == "j") {
            personSprite.attack();
            if (bossSprite) {
                bossSprite.hp -= 1
                bossHp.value = bossSprite.hp
                if (bossSprite.hp <= 0) {
                    isSuccess.value = true;
                }
            }
            enemySpriteList.forEach(enemySprite => {
                if (enemySprite.hp <= 0) return;
                let isBump = b.hit(personSprite.container, enemySprite.container);
                if (isBump) {
                    let arr = Array.from(keySet)
                    enemySprite.hurt();
                    if (arr.includes('a')) {
                        enemySprite.container.x -= 50
                    } else {
                        enemySprite.container.x += 50
                    }
                    if (enemySprite.hp <= 0) {
                        killNum.value += 1;
                        if (killNum.value == 10) {
                            if (guanqia.value == 4) {
                                isDead.value = true;
                            } else {
                                isSuccess.value = true;
                            }
                        }
                    }
                }
            });
            return;
        }
        if (keySet.size == 0) {
            personSprite.idle();
        }
    });

    window.addEventListener("resize", () => {
        app.renderer.resize(window.innerWidth, window.innerHeight);
        groundSprite.container.width = window.innerWidth;
        groundSprite.container.height = window.innerHeight;
    });
});
</script>

<style scoped>
.hp {
    position: absolute;
    left: 10px;
    top: 10px;
    font-size: 30px;
    color: red;
}

.info {
    position: absolute;
    left: 50%;
    top: 10px;
    font-size: 30px;
    transform: translate(-50%);
    color: black;
}

.setting-btn {
    width: max-content;
    padding: 5px 10px;
    font-size: 20px;
    position: absolute;
    top: 10px;
    right: 10px;
    color: white;
    border: 3px solid white;
    border-radius: 10px;
    cursor: pointer;
}

.setting {
    border: 3px solid black;
    border-radius: 10px;
    position: absolute;
    width: 400px;
    padding: 10px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(255, 255, 255, 0.9);
}

.setting .title {
    text-align: center;
    font-size: 30px;
}

.setting .close {
    position: absolute;
    right: 10px;
    top: 10px;
    cursor: pointer;
    font-size: 20px;
}

.setting .content {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.setting .content .btn {
    padding: 5px 20px;
    border-radius: 10px;
    font-size: 20px;
    text-align: center;
    border: 3px solid black;
    width: 200px;
    margin: 10px 0;
    cursor: pointer;
}

.dead-tip {
    border: 3px solid black;
    border-radius: 10px;
    position: absolute;
    width: 300px;
    padding: 10px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(255, 255, 255, 0.9);
    text-align: center;
}

.dead-tip .title {
    font-size: 20px;
    position: absolute;
    left: 10px;
}

.dead-tip p {
    margin-top: 30px;
}

.dead-tip .btn {
    padding: 5px 10px;
    border-radius: 10px;
    text-align: center;
    border: 2px solid black;
    width: max-content;
    margin: 10px auto;
    cursor: pointer;
}

.success-tip {
    border: 3px solid black;
    border-radius: 10px;
    position: absolute;
    width: 300px;
    padding: 10px;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: rgba(255, 255, 255, 0.9);
    text-align: center;
}

.success-tip .title {
    font-size: 20px;
    position: absolute;
    left: 10px;
}

.success-tip p {
    margin-top: 30px;
}

.success-tip .btn {
    padding: 5px 10px;
    border-radius: 10px;
    text-align: center;
    border: 2px solid black;
    width: max-content;
    margin: 10px auto;
    cursor: pointer;
}
</style>
